package cn.gov.pbc.dream.service.impl;

import cn.gov.pbc.dream.common.*;
import cn.gov.pbc.dream.common.BankFinancingMessageConst.Status;
import cn.gov.pbc.dream.dao.*;
import cn.gov.pbc.dream.pojo.bo.*;
import cn.gov.pbc.dream.pojo.query.bankfinancing.InfoQuery;
import cn.gov.pbc.dream.pojo.repository.*;
import cn.gov.pbc.dream.pojo.vo.bankfinancing.*;
import cn.gov.pbc.dream.service.IAreaService;
import cn.gov.pbc.dream.service.IBankFinancingService;
import cn.gov.pbc.dream.service.IFileService;
import cn.gov.pbc.dream.util.BigDecimalUtil;
import cn.gov.pbc.dream.util.DateTimeUtil;
import com.alibaba.excel.EasyExcel;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpSession;
import java.io.File;
import java.math.BigDecimal;
import java.util.*;

@Service("iBankFinancingService")
@Slf4j
public class BankFinancingServiceImpl implements IBankFinancingService {

    @Autowired
    private IFileService iFileService;

    @Autowired
    private IAreaService iAreaService;

    @Autowired
    private BankFinancingOrgDoMapper bankFinancingOrgDoMapper;

    @Autowired
    private AssetPoolDoMapper assetPoolDoMapper;

    @Autowired
    private BankFinancingProductInfoDoMapper bankFinancingProductInfoDoMapper;

    @Autowired
    private BankFinancingProductCurrencyDoMapper bankFinancingProductCurrencyDoMapper;

    @Autowired
    private BankFinancingProductCustomerDoMapper bankFinancingProductCustomerDoMapper;

    @Autowired
    private BankFinancingProductIncreaseCreditDoMapper bankFinancingProductIncreaseCreditDoMapper;

    @Autowired
    private BankFinancingProductIncreaseMethodDoMapper bankFinancingProductIncreaseMethodDoMapper;

    @Autowired
    private BankFinancingProductRaiseInfoDoMapper bankFinancingProductRaiseInfoDoMapper;

    @Autowired
    private BankFinancingProductTerminationInfoDoMapper bankFinancingProductTerminationInfoDoMapper;

    @Autowired
    private BankFinancingProductFundInfoDoMapper bankFinancingProductFundInfoDoMapper;


    @Override
    public ServerResponse uploadFile(HttpSession session, MultipartFile file, String destPath) {
        BankFinancingMessageResolveStatusBo statusBo = (BankFinancingMessageResolveStatusBo) session.
                getAttribute(BankFinancingMessageConst.RESOLVE_STATUS);
        if (statusBo != null && statusBo.getStatus().getCode() == BankFinancingMessageConst.Status.RUNNING.getCode()) {
            return ServerResponse.createByErrorMessage("解析任务正在运行，待完成后才能上传报文");
        }
        String destFileName = iFileService.uploadSingleFile(file, destPath);
        String originFileName = file.getOriginalFilename();
        Map<String, BankFinancingMessageInfoBo> uploadFilesMap = (Map<String, BankFinancingMessageInfoBo>) session.getAttribute(BankFinancingMessageConst.UPLOAD_FILES);
        if (uploadFilesMap == null) {
            uploadFilesMap = new HashMap<>();
            session.setAttribute(BankFinancingMessageConst.UPLOAD_FILES, uploadFilesMap);
        }
        if (uploadFilesMap.containsKey(originFileName)) {
            return ServerResponse.createByErrorMessage(String.format("%s文件重复，请全部重试", originFileName));
        }
        BankFinancingMessageInfoBo messageInfoBo = BankFinancingMessageInfoBo.from(originFileName,
                new File(destPath + File.separator + destFileName));
        if (messageInfoBo == null) {
            return ServerResponse.createByErrorMessage(String.format("%s文件名格式不符合规范", originFileName));
        }
        uploadFilesMap.put(originFileName, messageInfoBo);
        return ServerResponse.createBySuccess();
    }

    @Override
    public ServerResponse getUnresolveMessageList(HttpSession session) {
        List<String> list = new ArrayList<>();
        Map<String, BankFinancingMessageInfoBo> uploadFilesMap =
                (Map<String, BankFinancingMessageInfoBo>) session.
                        getAttribute(BankFinancingMessageConst.UPLOAD_FILES);
        if (uploadFilesMap == null) {
            return ServerResponse.createBySuccess(list);
        }
        for (Map.Entry<String, BankFinancingMessageInfoBo> item : uploadFilesMap.entrySet()) {
            list.add(item.getKey());
        }
        Collections.sort(list);
        return ServerResponse.createBySuccess(list);
    }

    @Override
    public ServerResponse deleteUpoladMessage(HttpSession session, String filename) {
        if (StringUtils.isBlank(filename)) {
            return ServerResponse.createByErrorCodeMessage(ResponseCode.ILLEGAL_ARGUMENT.getCode(),
                    ResponseCode.ILLEGAL_ARGUMENT.getDesc());
        }
        Map<String, BankFinancingMessageInfoBo> uploadFileMap =
                (Map<String, BankFinancingMessageInfoBo>) session.
                        getAttribute(BankFinancingMessageConst.UPLOAD_FILES);
        if (uploadFileMap == null) {
            return ServerResponse.createByErrorMessage("不存在该文件");
        }
        if (!uploadFileMap.containsKey(filename)) {
            return ServerResponse.createByErrorMessage("不存在该文件");
        }
        uploadFileMap.remove(filename);
        return ServerResponse.createBySuccess();
    }

    @Override
    public ServerResponse startResolveMessage(HttpSession session) {
        Map<String, BankFinancingMessageInfoBo> uploadFileMap =
                (Map<String, BankFinancingMessageInfoBo>) session.
                        getAttribute(BankFinancingMessageConst.UPLOAD_FILES);
        if (uploadFileMap == null || uploadFileMap.isEmpty()) {
            return ServerResponse.createByErrorMessage("请上传报文后解析");
        }
        BankFinancingMessageResolveStatusBo statusBo = (BankFinancingMessageResolveStatusBo) session.
                getAttribute(BankFinancingMessageConst.RESOLVE_STATUS);
        if (statusBo != null && statusBo.getStatus().getCode() == BankFinancingMessageConst.Status.RUNNING.getCode()) {
            return ServerResponse.createByErrorMessage("解析任务正在运行，待完成后才能上传报文");
        }
        //只要没有正在运行的解析任务就重新创新解析任务
        statusBo = this.initMessageResolveStatusBo(uploadFileMap);
        //设置状态为正在解析，并在seeesion中移除已上传的文件
        session.setAttribute(BankFinancingMessageConst.RESOLVE_STATUS, statusBo);
        session.removeAttribute(BankFinancingMessageConst.UPLOAD_FILES);
        new Thread(
                new BankFinancingMessageResolveThread(
                        uploadFileMap,
                        statusBo,
                        this.iAreaService,
                        this.bankFinancingOrgDoMapper,
                        this.assetPoolDoMapper,
                        this.bankFinancingProductInfoDoMapper,
                        this.bankFinancingProductCurrencyDoMapper,
                        this.bankFinancingProductCustomerDoMapper,
                        this.bankFinancingProductIncreaseCreditDoMapper,
                        this.bankFinancingProductIncreaseMethodDoMapper,
                        this.bankFinancingProductRaiseInfoDoMapper,
                        this.bankFinancingProductTerminationInfoDoMapper,
                        this.bankFinancingProductFundInfoDoMapper
                )
        ).start();
        return ServerResponse.createBySuccess();
    }

    //只有当开始运行报文解析任务的时候才会初始化报文状态BO
    private BankFinancingMessageResolveStatusBo initMessageResolveStatusBo
    (Map<String, BankFinancingMessageInfoBo> uploadFileMap) {
        BankFinancingMessageResolveStatusBo statusBo = new BankFinancingMessageResolveStatusBo();
        statusBo.setStatus(Status.RUNNING);
        statusBo.setStep(0);


        List<String> stepDescList = new ArrayList<>();
        stepDescList.add("开始");
        stepDescList.add("读取zip文件");
        stepDescList.add("分析");
        stepDescList.add("写入数据库");
        stepDescList.add("结束");
        statusBo.setStepDesc(stepDescList);
        return statusBo;
    }

    @Override
    public ServerResponse checkResolveMessageStatus(HttpSession session) {
        BankFinancingMessageResolveStatusBo statusBo = (BankFinancingMessageResolveStatusBo) session.
                getAttribute(BankFinancingMessageConst.RESOLVE_STATUS);
        MessageResolveStatusVo vo = new MessageResolveStatusVo();
        if (statusBo == null) {
            vo.setStatusCode(Status.EMPTY.getCode());
            vo.setStatusDesc(Status.EMPTY.getValue());
            return ServerResponse.createBySuccess(vo);
        }
        if (statusBo.getStatus().getCode() == Status.QUIT.getCode()) {
            return ServerResponse.createByErrorMessage(statusBo.getErrMsg());
        }
        vo.setStatusCode(statusBo.getStatus().getCode());
        vo.setStatusDesc(statusBo.getStatus().getValue());
        vo.setStep(statusBo.getStep());
        vo.setStepDescList(statusBo.getStepDesc());
        return ServerResponse.createBySuccess(vo);
    }

    @Override
    public ServerResponse getInfo(InfoQuery query) {
        PageHelper.startPage(query.getPageNum(), query.getPageSize());
        List<BankFinancingProductInfoDo> productInfoDoList =
                this.bankFinancingProductInfoDoMapper.selectByParam();
        List<InfoVo> productInfoVoList = new ArrayList<>();
        for (BankFinancingProductInfoDo productInfoDo : productInfoDoList) {
            productInfoVoList.add(this.assembleProductInfoVo(productInfoDo));
        }
        PageInfo pageInfo = new PageInfo(productInfoDoList);
        pageInfo.setList(productInfoVoList);
        return ServerResponse.createBySuccess(pageInfo);
    }

    private InfoVo assembleProductInfoVo(BankFinancingProductInfoDo infoDo) {
        InfoVo vo = new InfoVo();
        vo.setCode(infoDo.getCode());
        vo.setName(infoDo.getName());

        vo.setOrgName(this.bankFinancingOrgDoMapper.selectByPrimaryKey(infoDo.getBankFinancingOrgId()).getName());
        vo.setRunMethod(BankFinancingProductInfoConst.RunMethod.codeOf(infoDo.getRunMethod()).getValue());
        vo.setProductType(BankFinancingProductInfoConst.ProductType.codeOf(infoDo.getProductType()).getValue());
        if (infoDo.getHighestRateOfReturn() != null) {
            vo.setHighestRateOfReturn(infoDo.getHighestRateOfReturn().setScale(2, BigDecimal.ROUND_HALF_UP).toString());
        }
        if (infoDo.getLowestRateOfReturn() != null) {
            vo.setLowestRateOfReturn(infoDo.getLowestRateOfReturn().setScale(2, BigDecimal.ROUND_HALF_UP).toString());
        }


        return vo;
    }

    @Override
    public ServerResponse validateInfo(String month) {
        log.info("校验资金募集信息");
        if (StringUtils.isBlank(month)) {
            month = DateTimeUtil.dateToStr(new Date(), DateTimeUtil.DASH_MONTH);
        }
        List<BankFinancingProductTerminationInfoDo> terminationInfoDoList =
                this.bankFinancingProductTerminationInfoDoMapper.selectByReportMonth(month);
        List<BankFinancingValidateTerminalBo> terminalBoList = this.validateTerminal(terminationInfoDoList);
        this.writeValidateTerminalToExcel(terminalBoList);

        List<BankFinancingProductFundInfoDo> thisMonthFundInfo = this.bankFinancingProductFundInfoDoMapper.selectByRaiseMonth(month);
        if (thisMonthFundInfo.size() == 0) {
            log.warn(String.format("%s无资金募集信息", month));
        }
        List<BankFinancingProductFundInfoDo> lastMonthFundInfo = this.bankFinancingProductFundInfoDoMapper
                .selectByRaiseMonth(DateTimeUtil.getLastMonth(month));
        if (lastMonthFundInfo.size() == 0) {
            log.warn(String.format("%s的上月无资金募集信息", month));
        }
        BankFinancingValidator validator = new BankFinancingValidator(this.bankFinancingProductInfoDoMapper,
                this.iAreaService,
                this.bankFinancingOrgDoMapper);

        try {
            validator.validator(thisMonthFundInfo, lastMonthFundInfo);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        List<BalanceValidateExcel> balanceValidateExcelList = validator.getResultList();
        this.writeBalanceValidateExcel(balanceValidateExcelList);
        return ServerResponse.createBySuccess();
    }

    private void writeBalanceValidateExcel(List<BalanceValidateExcel> balanceValidateExcelList){
        EasyExcel.write("校验结果.xlsx", BalanceValidateExcel.class).sheet(0).doWrite(balanceValidateExcelList);
    }



    private void writeValidateTerminalToExcel(List<BankFinancingValidateTerminalBo> validateTerminalBoList) {
        List<TerminalValidateExcel> terminalValidateExcelList = new ArrayList<>(validateTerminalBoList.size());
        for (BankFinancingValidateTerminalBo terminalBo : validateTerminalBoList) {
            TerminalValidateExcel excelList = new TerminalValidateExcel();
            terminalValidateExcelList.add(excelList);
            excelList.setProductCode(terminalBo.getProductCode());
            excelList.setProductName(terminalBo.getProductName());
            excelList.setOrgName(terminalBo.getOrgName());
            excelList.setProductRaiseCurrencyType(terminalBo.getProductRaiseCurrencyType());
            excelList.setRunMethod(terminalBo.getRunMethod().getValue());
            excelList.setProductType(terminalBo.getCategory().getValue());
            excelList.setBusinessModel(terminalBo.getBusinessModel().getValue());
            excelList.setStartDate(DateTimeUtil.dateToStr(terminalBo.getStartDate(), DateTimeUtil.DASH_DATE_FORMAT));
            excelList.setEndDate(DateTimeUtil.dateToStr(terminalBo.getEndDate(), DateTimeUtil.DASH_DATE_FORMAT));
            excelList.setTerminateDate(DateTimeUtil.dateToStr(terminalBo.getTerminateDate(), DateTimeUtil.DASH_DATE_FORMAT));
            String abnormalInfo = terminalBo.getTerminateDate().compareTo(terminalBo.getEndDate()) > 0 ? "到期未兑付" : "提前终止";
            excelList.setAbnormalInfo(abnormalInfo);
            excelList.setNote(null);
        }
        EasyExcel.write("理财产品校验信息.xlsx", TerminalValidateExcel.class).sheet(0).doWrite(terminalValidateExcelList);
    }

    /**
     * 返回 理财产品实际到期日期与预期到终止日不符的数据
     *
     * @param terminationInfoDoList
     * @return
     */
    private List<BankFinancingValidateTerminalBo> validateTerminal(

            List<BankFinancingProductTerminationInfoDo> terminationInfoDoList) {
        //先去重
        Map<String, BankFinancingProductTerminationInfoDo> map = new HashMap<>();
        for (BankFinancingProductTerminationInfoDo terminationInfoDo : terminationInfoDoList) {
            if (map.containsKey(terminationInfoDo.getBankFinancingProductCode())) {
                continue;
            }
            if (terminationInfoDo.getTerminationDate() == null) {
                continue;
            }
            map.put(terminationInfoDo.getBankFinancingProductCode(), terminationInfoDo);
        }
        terminationInfoDoList = new ArrayList<>(map.values());


        List<BankFinancingValidateTerminalBo> terminalBoList = new ArrayList();
        for (BankFinancingProductTerminationInfoDo terminationInfoDo : terminationInfoDoList) {
            BankFinancingValidateTerminalBo terminalBo = new BankFinancingValidateTerminalBo();

            terminalBo.setProductCode(terminationInfoDo.getBankFinancingProductCode());
            terminalBo.setTerminateDate(terminationInfoDo.getTerminationDate());
            BankFinancingProductInfoDo productInfoDo = this.bankFinancingProductInfoDoMapper.selectByCode(terminationInfoDo.getBankFinancingProductCode());
            if (productInfoDo == null) {
                terminalBo.setProductCode("系统中没有该理财产品基本信息");
                terminalBoList.add(terminalBo);
                continue;
            }
            if (productInfoDo.getProductEndDate().equals(terminationInfoDo.getTerminationDate())) {
                continue;
            }
            terminalBo.setProductName(productInfoDo.getName());
            BankFinancingOrgDo orgDo =
                    this.bankFinancingOrgDoMapper.selectByPrimaryKey(productInfoDo.getBankFinancingOrgId());
            terminalBo.setOrgName(orgDo.getName());

            terminalBo.setIsEnd(false);

            BankFinancingProductCurrencyDo currencyDo =
                    this.bankFinancingProductCurrencyDoMapper.selectByProductCodeAndType(productInfoDo.getCode(),
                            BankFinancingProductInfoConst.CurrencyType.RAISED.getCode());

            terminalBo.setProductRaiseCurrencyType(currencyDo.getCode());
            terminalBo.setRunMethod(BankFinancingProductInfoConst.RunMethod.codeOf(productInfoDo.getRunMethod()));
            terminalBo.setCategory(BankFinancingProductInfoConst.Category.codeOf(productInfoDo.getCategory()));
            terminalBo.setBusinessModel(BankFinancingProductInfoConst.BusinessModel.codeOf(productInfoDo.getBusinessModel()));
            terminalBo.setStartDate(productInfoDo.getProductStartDate());
            terminalBo.setEndDate(productInfoDo.getProductEndDate());
            terminalBoList.add(terminalBo);
        }

        return terminalBoList;
    }
}
